---@class ExpeditionMapInfo
local MapInfo = Class("MapInfo")
function MapInfo:UpdateByMapDB(db)
    self.cfgId = db.cfgId
    self.buffId = db.buffId
    self.difficulty = self.cfgId--db.difficulty --难度不要了
end
---@class ExpeditionStageInfo
local StageInfo = Class("StageInfo")
function StageInfo:UpdateByStageDB(db)
    self.stageId = db.stageId
    self.state = db.state
    self.awardState = db.awardState
    self.power = db.power
    self.formation = {}
    for k,v in pairs(db.formation) do
        local f = {}
        f.modelId = v.modelId
        f.hp = v.hpRate  --百分，100位制
        f.energy = v.mpRate  --百分，100位制
        f.level = v.level
        table.insert(self.formation,f)
    end
    self.items = {}
    --装备补上 ,不在掉落
    --[[local drop = dataTable.getDataTableByMultiId("t_expeditionequipdrop",logicMgr.MapManager.getMapId(),self.stageId)
    if drop then
        local data ={};
        data["num"] = 1;
        data["itemModelId"] = drop.f_EquipDrop
        table.insert(self.items,data)
    end]]

    for k,v in pairs(db.items) do
        local data ={};
        data["num"] = v.num;
        data["itemModelId"] = v.itemModelId
        table.insert(self.items,data)
    end
end
function StageInfo:SetRewardState(state)
    self.awardState = state
end
---@class ExpeditionHeroInfo
local HeroInfo = Class("heroInfo")
function HeroInfo:UpdateByHeroDB(db)
    self.madelId = db.modelId
    self.partnerId = logicMgr.HeroManager.getHeroDatabyModelId(db.modelId,true).partnerId
    self.hp = db.hpRate         --百分，100位制
    self.energy = db.mpRate --百分，100位制
end

---@class ExpeditionMgr
ExpeditionMgr = {

}
ExpeditionMgr.StageState = {
    open = 1,
    reward = 2,
    rewardOver = 3,
    unlock = 4
}

ExpeditionMgr.MAX_LEVEL = 12
ExpeditionMgr.hasClickSweep = false
local t = ExpeditionMgr
local this = ExpeditionMgr
function ExpeditionMgr.init()
    this.isSelectMap = false
    ---@type ExpeditionMapInfo[]
    this.mapInfoList = {} --大地图数据
    ---@type ExpeditionStageInfo[]
    this.stageList = {}--关卡数据
    this.stageBuffList = {}  --buff
    ---@type ExpeditionHeroInfo[]
    this.heroInfoList = {}--伙伴血量信息
    this.isStartExpedition = true
    this.endTime = 0 --重置时间
    this.missCount = 0 --上次开启时间
    this.mapId = 0  --大区id
    this.mapDifficulty = 0  --大区难度
    this.resetCount = 0
    this.mapBuffId = 0
    this.showBuffId = {0,0,0}
    this.currentStageId = 0
    this.showExpeditionImmediate = false--战斗回来
    this.selectAwardIndex = 0--1温泉 2祭坛 3女神buff
    this.firstWardInfo = {}
    this.wards = {}
    this.canSweep = {}  --是否可以扫荡
    this.sweepCount = 0 --扫荡次数
    this.isMapView = true
    this.selectState = 2
    this.passRegionToday = {}--今天通关过的区域
    this.strength = 0   --远征体力值
    this.nextStrengthAddTime = 0    --下次体力补充的时间
    this.srvCDTime = 0  --服务器一开始发的已经CD了多久
    this.maxStrengthCfg = 0    --体力值上限（不含贵族加成）
    this.hasCDTime = 0  --CD打断前已经CD了多久
    this.maxStrength = 0 --最大体力值
end

---@return ExpeditionMapInfo
function t.GetMapInfo(id)
    return t.mapInfoList[id]
end
---@return ExpeditionStageInfo
function t.GetStageInfo(id)
    return t.stageList[id]
end
function t.GetStageCfg(difficulty,stageId)
    return dataTable.getDataTableByMultiId("t_expedition",difficulty,stageId)
end
function t.GetCurStageCfg(stageId)
    return  t.GetStageCfg(t.mapDifficulty,stageId)
end
function t.GetCurStageCfgParam(stageId,columnName)
    local cfg = t.GetCurStageCfg(stageId)
    if cfg and columnName then
        return cfg[columnName]
    end
    return cfg
end
---@return ExpeditionHeroInfo
function t.GetHeroInfo(partnerId)
    return t.heroInfoList[partnerId]
end
function t.RefreshTimeFinished()
    local num = dataTable.getDataTableByStringId("t_global",132,"f_int_value")
    t.endTime = 0--t.endTime + num * 24 * 3600
    t.resetCount = 1
end
--打完所有关卡，并领取了奖励
function t.IsCompleteAllStage()
    if #t.stageList == 0 then
        return false
    end
    for k,v in pairs(t.stageList) do
        local full = t.GetStageFullState(k)
        if full == t.StageState.open or full == t.StageState.unlock then
            return false
        end
    end
    return true
end
--打完所有关卡，并领取了奖励
function t.IsGetAllStageReward()
    for k,v in pairs(t.stageList) do
        local full = t.GetStageFullState(k)
        if full ~= t.StageState.rewardOver then
            return false
        end
    end
    return true
end
---@return ExpeditionStageInfo
function t.GetCurrentStage()
    return t.stageList[t.GetCurStageId()]
end
function t.GetCurStageId()
    return t.currentStageId
end
function t.SetCurStageId(id)
    t.currentStageId = id
end
function t.IsDead(partnerId)
    local info = t.GetHeroInfo(partnerId)
    if not info then return false end
    return info.hp == 0
end
function t.GetStageFullState(id)
    local info = t.stageList[id]
    if info then
        if id == t.currentStageId and info.state ~= 1 then
            return t.StageState.open
        elseif info.state == 1 then
            return t.StageState.rewardOver
            --[[if info.awardState == 0 then
                return t.StageState.reward
            else
                return t.StageState.rewardOver
            end]]
        end
    end

    return t.StageState.unlock

end
function t.GetNeedRecoverHero()
    local tb = logicMgr.HeroManager.getOwnerHeroList()
    table.sort(tb,logicMgr.HeroManager.sortHero)
    return tb
end
function t.SetHeroDeadFlag()
    for k,v in pairs(t.heroInfoList) do
        if v.hp == 0 then
            logicMgr.HeroManager.setHeroState(v.partnerId,true,EnumConst.HeroHeadStateEnum.DEAD)
        end
    end
end
function t.ClearHeroDeadFlag()
    for k,v in pairs(t.heroInfoList) do
        if v.hp == 0 then
            logicMgr.HeroManager.setHeroState(v.partnerId,false,EnumConst.HeroHeadStateEnum.DEAD)
        end
    end
end
function t.SetWard(wards)
    t.wards = wards
end
function t.MapFistWardInfo(info)
    t.firstWardInfo = info
end

function t.RefreshMapFistWardInfo( cfgId ) 
    if t.firstWardInfo ~= nil and next(t.firstWardInfo) == nil then
        table.insert(t.firstWardInfo, cfgId)
    end
end

-- 判断是否完成首通
function t.IsCompletedFirst()
    if t.firstWardInfo ~= nil and next(t.firstWardInfo) ~= nil then
        return true
    end
    return false
end


function t.FirstWardHasGet(cfgId)
    if t.firstWardInfo ~= nil then
        for _, v in pairs(t.firstWardInfo) do
            if v and v == cfgId then
                return true
            end
        end
    end
    return false
end

function t.AddMapInfo(db)
    local info = t.mapInfoList[db.cfgId]
    if info == nil then
        info = MapInfo.New()
        t.mapInfoList[db.cfgId] = info
    end
    info:UpdateByMapDB(db)
end
function t.ClearStage()
    table.clear(t.stageList)
    table.clear(t.stageBuffList)
    t.mapBuffId = 0
    t.showBuffId = {0, 0, 0}
    t.currentStageId = -1
    t.isStartExpedition = false
    t.selectAwardIndex = 0
end

function t.SetSelectAwardIndex(index)
    t.selectAwardIndex = index    
end

function t.ClearSelectAwardIndex()
    t.selectAwardIndex = 0
end

function t.ClearHeroList()
    table.clear(t.heroInfoList)
end
function t.AddStageInfo(db)
    local info = StageInfo.New()
    info:UpdateByStageDB(db)
    t.stageList[info.stageId] = info
end
function t.SetStageState(stageId,state)
    local info = t.stageList[stageId]
    if info then
        info.state = state
    end
end
function t.SetStageAwardState(stageId,state,buffId)
    local info = t.stageList[stageId]
    if info then
        info.awardState = state
    end
end
function t.AddStageBuff(buffId)
    table.insert(t.stageBuffList,buffId)
end
function t.ClearShowBuff()
    t.showBuffId = {0,0,0}
end
function t.AddShowBuff(buffId)
    for k,v in pairs(buffId) do
        t.showBuffId[k] = v
    end
end
function t.AddHeroList(db)
    local info = HeroInfo.New()
    info:UpdateByHeroDB(db)

    -- if t.selectAwardIndex == EnumConst.ExpeditionAwardType.Altar then
    --     local hero = t.heroInfoList[info.partnerId]
    --     if hero and hero.hp == 0 and db.hpRate > 0 then
    --         --logError("神圣祭坛复活英雄")
    --         TAManager.TrackByDictionary("expedition_choose_altar", {hero_id = tostring(info.madelId)})
    --     end
    -- elseif t.selectAwardIndex == EnumConst.ExpeditionAwardType.Hotspring then
    --     local hero = t.heroInfoList[info.partnerId]
    --     if hero and hero.hp < db.hpRate then
    --         -- logError("迷雾温泉回血英雄")
    --         TAManager.TrackByDictionary("expedition_choose_spring", {hero_id = tostring(info.madelId), hp_return = tostring(db.hpRate - hero.hp)})
    --     end
    -- end

    t.heroInfoList[info.partnerId] = info

end
function t.ClickReset()
    if logicMgr.ExpeditionMgr.resetCount == 0 then
        return
    end
    if logicMgr.ExpeditionMgr.IsGetAllStageReward() then
        ExpeditionHandler.ReqResetExpedition()
    else
        logicMgr.UIShowManager.ShowCommonConfirm(getLanguage("expedition_reset_confirm_tip"),nil,
        function()
            ExpeditionHandler.ReqResetExpedition()
        end,nil,self)
    end
end
function t.SetRedPoint(stats)
    this.redPointStats = stats;
end

function t.HasRedPoint()
    --for k,v in pairs(t.stageList) do
    --    local type = t.GetCurStageCfgParam(v.stageId,"f_ExpeditionType")
    --    if t.GetStageFullState(v.stageId) == t.StageState.reward and  type >= 2 then
    --            return true
    --    end
    --end
    --if t.endTime <= HelperFunc.GetServerTime() then
    --    return true
    --end
    return this.redPointStats;
end

function t.HasSweepRedPoint()
    --打完最后一关且还有远征券，点完一次消失，远征使用体力值，废弃了
    --local curSweepCount = logicMgr.ExpeditionMgr.GetSweepCount()
    --local maxSweepCount = tonumber(G.dataTable["t_global"][tostring(383)]["f_string_value"])
    --local ticketCount = logicMgr.ItemManager.getItemCountbyModelId(CurrencyEnum.ExpeditionTicket);
    --if t.IsCompleteAllStage() and ticketCount > 0 and not t.hasClickSweep and curSweepCount < maxSweepCount then
        --return true
    --else
        --return false
    --end
    local curStrength = logicMgr.ExpeditionMgr.strength
    local cfgInfo = G.dataTable["t_global"][tostring(595)]["f_string_value"]
    local strengthSweepCost = 0
    if cfgInfo and cfgInfo[3] and tonumber(cfgInfo[3]) > 0 then
        strengthSweepCost = tonumber(cfgInfo[3])
    end
    if curStrength >= strengthSweepCost then
        return true
    else
        return false
    end
end

function t.SetClickSweep(hasClick)
    t.hasClickSweep = hasClick
end

function t.GetPassNum()
    local buffs = logicMgr.EcoBuffManager.getEcoBuffByTypeAndItemId(Config.EcoBuffCondition.LongJourneySelectTimes);
    if buffs > 0 and t.missCount > 0 then
        return buffs * t.missCount;
    end
    return 0;
end


function t.SetCanSweep(canSweep)
    t.canSweep = canSweep
end

function t.GetCanSweep()
    return t.canSweep  or 0;
end

function t.SetSweepCount(num)
    t.sweepCount = num
end

function t.GetSweepCount()
    return t.sweepCount  or 0;
end

function t.SetResetType(resetTyoe)
    t.resetType = resetTyoe
end

function t.GetResetType()
    return t.resetType
end

--下一次回复体力值的时间戳
function t.GetNextRefreshEnergyTime()
    if t.IsEnergyFull() then
        return 0
    else
        if t.GetHasCDTime() > 0 then
            t.nextStrengthAddTime = t.nextStrengthAddTime - t.GetHasCDTime()
            t.SetHasCDTime(0)
        end
        return t.nextStrengthAddTime
    end
end

--体力值回满的时间戳
function t.GetEnergyFullTime()
    if t.IsEnergyFull() then
        return 0
    else
        local remainStrength = t.GetFullEnergy() - t.strength -1
        local rate = G.dataTable["t_global"][tostring(595)]["f_string_value"][2]    --回满体力需要的多少秒
        if rate and rate > 0 then
            return remainStrength * rate + t.GetNextRefreshEnergyTime()
        end
    end
end

--判断体力值是否满了
function t.IsEnergyFull()
    return t.strength >= t.GetFullEnergy()
end

--当前体力值上限
function t.GetFullEnergy()
    --if t.maxStrengthCfg and t.maxStrengthCfg > 0 then
    --    local cfgInfo = G.dataTable["t_global"][tostring(595)]["f_string_value"]
    --    if cfgInfo and cfgInfo[4] and cfgInfo[4] > 0 then
    --        t.maxStrengthCfg = cfgInfo[4]
    --    end
    --end
    ----判断是否有贵族特权
    --local buffAdd = logicMgr.EcoBuffManager.getEcoBuffByTypeAndItemId(Config.EcoBuffCondition.LongJourneyStrengthAdd);
    --return t.maxStrengthCfg + buffAdd
    return this.maxStrength
end

--CD时被打断，需要记录当前已经CD了多久，下次减去这个CD
function t.SetHasCDTime(hasCDTime)
    if tonumber(hasCDTime) and tonumber(hasCDTime) >= 0 then
        t.hasCDTime = hasCDTime
    end
end

function t.GetHasCDTime()
    return t.hasCDTime
end

--道具增加体力值
function t.AddStrength(addStrength)
    if addStrength and addStrength > 0 then
        local perStrengthCostSec = 0    --每回复一点体力值，需要的时间
        local cfgInfo = G.dataTable["t_global"][tostring(595)]["f_string_value"]
        if cfgInfo and cfgInfo[2] and tonumber(cfgInfo[2]) > 0 then
            perStrengthCostSec = tonumber(cfgInfo[2])
        end
        if t.strength < t.GetFullEnergy() and t.strength + addStrength >= t.GetFullEnergy() then    --原本没满在CD中，加满了，记录CD了多久
            --t.SetHasCDTime(perStrengthCostSec - t.nextStrengthAddTime - HelperFunc.GetServerTime())
            t.srvCDTime = perStrengthCostSec - (t.nextStrengthAddTime - HelperFunc.GetServerTime())
            t.nextStrengthAddTime = 0
        end
        t.strength = t.strength + addStrength
    else
        t.strength = t.strength + 1
        if t.IsEnergyFull() then
            t.nextStrengthAddTime = 0
        end
    end
	FireEvent(Config.EventType.ExpeditionSweepRefresh)
end

--自然恢复体力值
function t.RecoverStrength()
    if t.IsEnergyFull() then
        t.nextStrengthAddTime = 0
    else
        t.strength = t.strength + 1
        if t.IsEnergyFull() then
            t.srvCDTime = 0
        end
        local perStrengthCostSec = 0    --每回复一点体力值，需要的时间
        local cfgInfo = G.dataTable["t_global"][tostring(595)]["f_string_value"]
        if cfgInfo and cfgInfo[2] and tonumber(cfgInfo[2]) > 0 then
            perStrengthCostSec = tonumber(cfgInfo[2])
            t.nextStrengthAddTime =  HelperFunc.GetServerTime() + perStrengthCostSec
        end
    end
	FireEvent(Config.EventType.ExpeditionSweepRefresh)
end

--减少体力值
function t.ReduceStrength(reduceStrength)
    if reduceStrength and reduceStrength > 0 then
        local perStrengthCostSec = 0    --每回复一点体力值，需要的时间
        local cfgInfo = G.dataTable["t_global"][tostring(595)]["f_string_value"]
        if cfgInfo and cfgInfo[2] and tonumber(cfgInfo[2]) > 0 then
            perStrengthCostSec = tonumber(cfgInfo[2])
        end
        if t.IsEnergyFull() and t.strength - reduceStrength < t.GetFullEnergy() then    --原本满的，消耗后没满，开始CD
            t.nextStrengthAddTime = HelperFunc.GetServerTime() + perStrengthCostSec - this.srvCDTime
            this.srvCDTime = 0
            t.SetHasCDTime(0)
        end
        t.strength = t.strength - reduceStrength
    else
        t.strength = t.strength - 1
    end
	FireEvent(Config.EventType.ExpeditionSweepRefresh)
end

return ExpeditionMgr